const fs = require('fs');
const parser = require('@babel/parser')
//兼容性的包挂载default上面
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')
const path = require('path')

//对模块今夕一个ID
let ID = 0;
function createAsset (filename) {
 const content =  fs.readFileSync(filename,'utf-8');
 //解析这个文件,指定文件类型为依赖类型
 const ast = parser.parse(content,{
   sourceType:'module'
 })
  const dependencies = [];
 // 找到import节点
  traverse(ast,{
    ImportDeclaration:({node})=>{
      dependencies.push(node.source.value)
    }
  })
  //preset与plugin的区别
  const {code} = babel.transformFromAstSync(ast,null,{
    presets:['@babel/preset-env'],
    plugins:[]
  })
  let id = ID++;
  // parser.parse(content)
  return {
    id,
    filename,
    code,
    dependencies,

  }
}

function createGraph (entry) {
  const mainAsset = createAsset(entry)
  const queue = [mainAsset]
  //构建队列,将分析出来的index的AST放进去

  for(const asset of queue){
    //相对路径
    const dirname = path.dirname(asset.filename);
    asset.mapping = {}
    asset.dependencies.forEach(
      relativePath=>{
        const absolutePath =  path.join(dirname,relativePath);
        const child = createAsset(absolutePath)
        asset.mapping[relativePath] = child.id
        queue.push(child)
      })
  }
  return queue;
}

/**
 * 打包分析出来的依赖图,使用立即执行函数去执行图中的每段代码
 * @param graph
 */
function bundle(graph){
  let modules = '';
  graph.forEach(
    mod =>{
      modules += `
      ${mod.id}:[
        function (require,module,exports) {
          ${mod.code}
        },
        ${JSON.stringify(mod.mapping)}
      ],`}
  )
  const result = `
    (function(modules){
      function require(id){
        const [fn,mapping] = modules[id];
        
        function localRequire(relativePath){
         return require(mapping[relativePath])
        }
        
        const module = {
          exports:{}
        }
        
        fn(localRequire,module,module.exports)
        return module.exports;
      }
      require(0);
    })({${modules}});
  `
  return result;
}
// const asset = createAsset('./src/index.js')

const graph = createGraph ('./src/index.js')
const result = bundle(graph);
console.log(result);